package gbench.common.matlib.matrix;

import java.lang.reflect.Array;
import java.text.NumberFormat;
import java.util.*;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.IntFunction;
import java.util.function.Predicate;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 矩阵操作&计算库
 */
public class MatrixOps {

    /**
     * 构造出一个整型数字的流，数组从0开始，0,1,2,...
     *
     * @return 整型的流
     */
    public static Stream<Integer> stm() {
        return Stream.iterate(0, i -> i + 1);
    }

    /**
     * 构造出一个整型数字的流，数组从0开始，0,1,2,... maxSize-1
     *
     * @return 整型的流
     */
    public static Stream<Integer> stm(final Number maxSize) {
        return stm().limit(maxSize.longValue());
    }

    /**
     * 构造出一个整型数字的流，数组从0开始，0,1,2,... maxSize-1 <br>
     * 带有过滤条件 predicate
     *
     * @return 整型的流
     */
    public static Stream<Integer> stm(final Number maxSize, final Predicate<Integer> predicate) {
        return stm(maxSize).filter(predicate);
    }

    /**
     * 返回一个二维数组的 维度长度
     *
     * @param tt  二维数组
     * @param <T> 二维数组的元素
     * @return 数字的形状
     */
    public static <T> Tuple2<Integer, Integer> shape(final T[][] tt) {
        return new Tuple2<>(tt.length, S(tt).collect(Collectors.summarizingInt(t -> t.length)).getMax());
    }

    /**
     * 数组生成器
     *
     * @param clazz 数组元素的类型类
     * @param <T>   数组元素的类型
     * @return 数组生成器
     */
    @SuppressWarnings("unchecked")
    public static <T> IntFunction<T[]> arr(final Class<T> clazz) {
        final var tclass = clazz == null ? (Class<T>) Object.class : clazz;
        return n -> (T[]) Array.newInstance(tclass, n);
    }

    /**
     * 数组生成器
     *
     * @param tclazz 数组元素的类型类
     * @param <T>    数组元素的类型
     * @return 数组生成器
     */
    @SuppressWarnings("unchecked")
    public static <T> IntFunction<T[][]> arr2(final Class<T> tclazz) {
        return n -> (T[][]) Array.newInstance(tclazz, n, 1);
    }

    /**
     * 二维数据遍历
     *
     * @param m     第一维索引长度
     * @param n     第二维索引长度
     * @param fxy   维度索引遍历函数
     * @param clazz 元素类型类
     * @param <T>   元素类型
     * @return T类型的二维数组
     */
    @SuppressWarnings("unchecked")
    public static <T> T[][] ij_yield(final int m, final int n, BiFunction<Integer, Integer, T> fxy, final Class<?> clazz) {
        final var tclass = clazz == null ? (Class<T>) Object.class : clazz;
        return stm(m).map(i -> stm(n).map(j -> fxy.apply(i, j)).toArray(arr(tclass)))
                .toArray(size -> (T[][]) Array.newInstance(tclass, size, 1));
    }

    /**
     * 二维数据遍历
     *
     * @param m   第一维索引长度
     * @param n   第二维索引长度
     * @param fxy 维度索引遍历函数
     * @param <T> 元素类型
     * @return T类型的二维数组
     */
    public static <T> T[][] ij_yield(final int m, final int n, final BiFunction<Integer, Integer, T> fxy) {
        return ij_yield(m, n, fxy, fxy.apply(0, 0).getClass());
    }

    /**
     * 二维数据遍历
     *
     * @param tt  二维数组
     * @param <T> 元素类型
     * @return T类型的二维数组
     */
    public static <T> T[][] transpose(final T[][] tt) {
        final var shape = shape(tt);
        return ij_yield(shape._2, shape._1, (i, j) -> tt[j][i], tt.getClass().getComponentType().getComponentType());
    }

    /**
     * 向量点集（结果向量的长度为两个参数响亮的较长的那个向量的长度，对短的向量采用循环补位进行补填）
     *
     * @param tt  第一向量
     * @param uu  第二向量
     * @param <T> 第一向量的的 元素类型
     * @param <U> 第二向量的的 元素类型
     * @return 点集结果
     */
    public static <T extends Number, U extends Number> Double dot(final T[] tt, final U[] uu) {
        return Tuple2.zip(tt, uu).map(p -> p._1.doubleValue() * p._2.doubleValue()).reduce(0d, Double::sum);
    }

    /**
     * 向量加法（结果向量的长度为两个参数响亮的较长的那个向量的长度，对短的向量采用循环补位进行补填）
     *
     * @param tt  第一向量
     * @param uu  第二向量
     * @param <T> 第一向量的的 元素类型
     * @param <U> 第二向量的的 元素类型
     * @return 向量加法
     */
    public static <T extends Number, U extends Number> Double[] add(final T[] tt, final U[] uu) {
        return Tuple2.zip(tt, uu).map(p -> p._1.doubleValue() + p._2.doubleValue()).toArray(arr(Double.class));
    }

    /**
     * 向量加法（结果向量的长度为两个参数响亮的较长的那个向量的长度，对短的向量采用循环补位进行补填）
     *
     * @param t   第二向量 单值元素
     * @param uu  第一向量
     * @param <T> 第二向量的的 元素类型
     * @param <U> 第一向量的的 元素类型
     * @return 向量加法
     */
    public static <T extends Number, U extends Number> Double[] add(final U[] uu, final T t) {
        return add(A(t), uu);
    }

    /**
     * 向量加法（结果向量的长度为两个参数响亮的较长的那个向量的长度，对短的向量采用循环补位进行补填）
     *
     * @param t   第一向量 单值元素
     * @param uu  第二向量
     * @param <T> 第一向量的的 元素类型
     * @param <U> 第二向量的的 元素类型
     * @return 向量加法
     */
    public static <T extends Number, U extends Number> Double[] add(final T t, final U[] uu) {
        return add(A(t), uu);
    }

    /**
     * 向量减法（结果向量的长度为两个参数响亮的较长的那个向量的长度，对短的向量采用循环补位进行补填）
     *
     * @param tt  第一向量
     * @param uu  第二向量
     * @param <T> 第一向量的的 元素类型
     * @param <U> 第二向量的的 元素类型
     * @return 向量减法
     */
    public static <T extends Number, U extends Number> Double[] sub(final T[] tt, final U[] uu) {
        return Tuple2.zip(tt, uu).map(p -> p._1.doubleValue() - p._2.doubleValue()).toArray(arr(Double.class));
    }

    /**
     * 向量减法（结果向量的长度为两个参数响亮的较长的那个向量的长度，对短的向量采用循环补位进行补填）
     *
     * @param t   第一向量 单值元素
     * @param uu  第二向量
     * @param <T> 第一向量的的 元素类型
     * @param <U> 第二向量的的 元素类型
     * @return 向量减法
     */
    public static <T extends Number, U extends Number> Double[] sub(final T t, final U[] uu) {
        return add(A(t), uu);
    }

    /**
     * 向量减法（结果向量的长度为两个参数响亮的较长的那个向量的长度，对短的向量采用循环补位进行补填）
     *
     * @param t   第二向量 单值元素
     * @param uu  第一向量
     * @param <T> 第二向量的的 元素类型
     * @param <U> 第一向量的的 元素类型
     * @return 向量减法
     */
    public static <T extends Number, U extends Number> Double[] sub(final U[] uu, final T t) {
        return add(A(t), uu);
    }

    /**
     * 向量乘法（结果向量的长度为两个参数响亮的较长的那个向量的长度，对短的向量采用循环补位进行补填）
     *
     * @param tt  第一向量
     * @param uu  第二向量
     * @param <T> 第一向量的的 元素类型
     * @param <U> 第二向量的的 元素类型
     * @return 向量乘法
     */
    public static <T extends Number, U extends Number> Double[] mul(final T[] tt, final U[] uu) {
        return Tuple2.zip(tt, uu).map(p -> p._1.doubleValue() * p._2.doubleValue()).toArray(arr(Double.class));
    }

    /**
     * 向量乘法（结果向量的长度为两个参数响亮的较长的那个向量的长度，对短的向量采用循环补位进行补填）
     *
     * @param t   第一向量 单值元素
     * @param uu  第二向量
     * @param <T> 第一向量的的 元素类型
     * @param <U> 第二向量的的 元素类型
     * @return 向量乘法
     */
    public static <T extends Number, U extends Number> Double[] mul(final T t, final U[] uu) {
        return mul(A(t), uu);
    }

    /**
     * 向量乘法（结果向量的长度为两个参数响亮的较长的那个向量的长度，对短的向量采用循环补位进行补填）
     *
     * @param t   第二向量 单值元素
     * @param uu  第一向量
     * @param <T> 第二向量的的 元素类型
     * @param <U> 第一向量的的 元素类型
     * @return 向量乘法
     */
    public static <T extends Number, U extends Number> Double[] mul(final U[] uu, final T t) {
        return mul(A(t), uu);
    }

    /**
     * 向量除法（结果向量的长度为两个参数响亮的较长的那个向量的长度，对短的向量采用循环补位进行补填）
     *
     * @param tt  第一向量 被除数
     * @param uu  第二向量 除数
     * @param <T> 第一向量的的 元素类型
     * @param <U> 第二向量的的 元素类型
     * @return 向量除法
     */
    public static <T extends Number, U extends Number> Double[] div(final T[] tt, final U[] uu) {
        return Tuple2.zip(tt, uu).map(p -> p._1.doubleValue() / p._2.doubleValue()).toArray(arr(Double.class));
    }
    
    /**
     * 向量除法（结果向量的长度为两个参数响亮的较长的那个向量的长度，对短的向量采用循环补位进行补填）
     *
     * @param tt  第一向量 被除数
     * @param u   第二向量 单值元素 除数
     * @param <T> 第一向量的的 元素类型
     * @param <U> 第二向量的的 元素类型
     * @return 向量除法
     */
    public static <T extends Number, U extends Number> Double[] div(final T[] tt, final U u) {
        return div(tt,A(u));
    }

    /**
     * 向量除法（结果向量的长度为两个参数响亮的较长的那个向量的长度，对短的向量采用循环补位进行补填）
     *
     * @param t   第一向量 单值元素 被除数
     * @param uu  第二向量 除数
     * @param <T> 第一向量的的 元素类型
     * @param <U> 第二向量的的 元素类型
     * @return 向量除法
     */
    public static <T extends Number, U extends Number> Double[] div(final T t, final U[] uu) {
        return add(A(t), uu);
    }

    /**
     * 向量除法（结果向量的长度为两个参数响亮的较长的那个向量的长度，对短的向量采用循环补位进行补填）
     *
     * @param tt  第一向量 除数
     * @param uu  第二向量 被除数
     * @param <T> 第一向量的的 元素类型
     * @param <U> 第二向量的的 元素类型
     * @return 向量除法
     */
    public static <T extends Number, U extends Number> Double[] div2(final T[] tt, final U[] uu) {
        return Tuple2.zip(uu, tt).map(p -> p._1.doubleValue() / p._2.doubleValue()).toArray(arr(Double.class));
    }

    /**
     * 向量除法（结果向量的长度为两个参数响亮的较长的那个向量的长度，对短的向量采用循环补位进行补填）
     *
     * @param t   第一向量 单值元素 除数
     * @param uu  第二向量 被除数
     * @param <T> 第一向量的的 元素类型
     * @param <U> 第二向量的的 元素类型
     * @return 向量除法
     */
    public static <T extends Number, U extends Number> Double[] div2(final T t, final U[] uu) {
        return div2(A(t), uu);
    }

    /**
     * 矩阵乘法
     *
     * @param tt  左乘矩阵 m x p
     * @param uu  右乘矩阵 p x n
     * @param <T> 左乘矩阵 元素类型
     * @param <U> 右边乘矩阵 元素类型
     * @return 结果矩阵 m x n
     */
    public static <T extends Number, U extends Number> Double[][] mmult(final T[][] tt, final U[][] uu) {
        final var shape = new Tuple2<>(shape(tt)._1, shape(uu)._2);
        final var ss = transpose(uu);
        return ij_yield(shape._1, shape._2, (i, j) -> dot(tt[i], ss[j]), Double.class);
    }
    
    /**
     * 矩阵乘法 函数  (uncurry mmult):参数矩阵tt为左乘参数
     *
     * @param tt  右乘矩阵 p x n
     * @param <T> 左乘矩阵 元素类型
     * @param <U> 右边乘矩阵 元素类型
     * @return 结果矩阵 m x n
     */
    public static <T extends Number, U extends Number> Function<U[][],Double[][]> lmmult(final T[][] tt) {
        
        return uu -> mmult(tt,uu);
    }
    
    /**
     * 矩阵乘法 (uncurry mmult)：参数矩阵uu为右乘矩阵
     *
     * @param uu  右乘矩阵 p x n
     * @param <T> 左乘矩阵 元素类型
     * @param <U> 右边乘矩阵 元素类型
     * @return 结果矩阵 m x n
     */
    public static <T extends Number, U extends Number> Function<T[][],Double[][]> rmmult(final U[][] uu) {
        
        return tt -> mmult(tt,uu);
    }

    /**
     * 求出一个矩阵的 [_i,_j] 的余子式
     *
     * @param tt  方形 矩阵  nxn
     * @param _i  第一维度的索引值，行索引 从0开始
     * @param _j  第二维度的索引值，行索引 从0开始
     * @param <T> 矩阵的元素的类型
     * @return 矩阵的 (_i,_j) 余子式
     */
    @SuppressWarnings("unchecked")
    public static <T> T[][] minor(final T[][] tt, final int _i, final int _j) {
        final var shape = shape(tt);
        final var c1 = (Class<T[]>) tt.getClass().getComponentType();
        final var c2 = c1.getComponentType();
        return stm(shape._1, i -> i != _i).map(i -> stm(shape._2, j -> j != _j).map(j -> tt[i][j]).toArray(arr(c2))).toArray(arr(c1));
    }

    /**
     * 计算一个矩阵/方阵的行列式
     *
     * @param tt  矩阵 方阵 nxn
     * @param <T> 矩阵的元素
     * @return 矩阵/方阵的行列式
     */
    public static <T extends Number> Double det(final T[][] tt) {
        final var shape = shape(tt);
        return shape._2 == 1 && shape._1 == 1
                ? tt[0][0].doubleValue()
                : stm(shape._1).map(i -> tt[i][0].doubleValue() * det(minor(tt, i, 0)) * (i % 2 == 0 ? 1 : -1))
                .reduce(0d, Double::sum);
    }

    /**
     * 把 一个元素序列 ts 转换成一个 结构
     *
     * @param ts  元素序列
     * @param <T> 元素类型
     * @return 元素序列的流
     */
    @SafeVarargs
    public static <T> Stream<T> S(T... ts) {
        return Stream.of(ts);
    }


    /**
     * 把 一个元素序列 ts 转换成一个 数组结构
     *
     * @param ts  元素序列
     * @param <T> 元素类型
     * @return 元素序列的数组
     */
    @SafeVarargs
    public static <T> T[] A(T... ts) {
        return ts;
    }

    /**
     * 把 一个元素序列 ts 转换成一个 列表结构
     *
     * @param ts  元素序列
     * @param <T> 元素类型
     * @return 元素序列的列表
     */
    @SafeVarargs
    public static <T> List<T> L(T... ts) {
        return Arrays.asList(ts);
    }

    /**
     * 把 一个元素列表 tt 转换成一个 数组结构
     *
     * @param tt  元素列表
     * @param <T> 元素类型
     * @return 元素序列的列表
     */
    @SuppressWarnings("unchecked")
    public static <T> T[] L2A(final List<T> tt) {
        final var tclass = tt.stream().filter(Objects::nonNull)
                .map(e -> (Class<T>) e.getClass()).findFirst().orElse((Class<T>) Object.class);
        return tt.toArray(arr(tclass));
    }

    /**
     * 把一个t类型的元素插入到一个数组的首前位置，即成为新数组的头元素。
     *
     * @param t   前首元素
     * @param tt  尾部徐略
     * @param <T> 数组的元素类型
     * @return 新生成的数组
     */
    @SuppressWarnings("unchecked")
    public static <T> T[] CONS(final T t, final T[] tt) {
        return Stream.concat(S(t), S(tt)).toArray(arr((Class<T>) tt.getClass().getComponentType()));
    }

    /**
     * 把一个 一维数组1xn转换成一个二维数组nx1
     *
     * @param ts  一维数组，元素元素序列
     * @param <T> 元素类型
     * @return 二维数组nx1
     */
    @SafeVarargs
    public static <T> T[][] V(final T... ts) {
        return transpose(RPTA(1, A(ts)));
    }

    /**
     * 把一个 一维数组1xm转换成一个二维数组m x n 的函数 <br>
     * Verticalize And repeatT <br>
     * @param <T> 元素类型
     * @return 二维数组m x n 的生成函数 ts-> [t1;t2;...;tn] 的列向量数组，ts 是长度为m的一维数组
     */
    public static <T> Function<T[], T[][]> VT(final int n) {
        return ts -> transpose(RPTA(n, ts));
    }

    /**
     * 把一个 一维数组转化成一个二维数组 矩阵
     *
     * @param m   第一维长度 行数
     * @param n   第二维长度 列数
     * @param <T> 元素类型
     * @return 二维数组 矩阵
     */
    public static <T> Function<T[], T[][]> vt2mx(final int m, final int n) {
        return tt -> ij_yield(m, n, (i, j) -> tt[(j + i * n) % tt.length], tt.getClass().getComponentType());
    }

    /**
     * 二维数组 矩阵的搜集器
     *
     * @param vt2mx 一维数组转化成一个二维数组 矩阵 变换函数
     * @param <T>   元素类型
     * @return 二维数组 矩阵的搜集器
     */
    public static <T> Collector<T, List<T>, T[][]> mxclc(final Function<List<T>, T[][]> vt2mx) {
        return Collector.of(ArrayList::new, List::add, (aa, bb) -> {
            aa.addAll(bb);
            return bb;
        }, vt2mx);
    }

    /**
     * 二维数组 矩阵的搜集器
     *
     * @param m   第一维长度 行数
     * @param n   第二维长度 列数
     * @param <T> 元素类型
     * @return 二维数组 矩阵的搜集器
     */
    @SuppressWarnings("unchecked")
    public static <T> Collector<T, List<T>, T[][]> mxclc(final int m, final int n) {
        return mxclc(tt -> (T[][]) vt2mx(m, n).apply(L2A(tt)));
    }

    /**
     * 二维元组
     *
     * @param <T> 第一位置 元素类型
     * @param <U> 第而位置 元素类型
     */
    public static class Tuple2<T, U> {

        /**
         * @param _1 第一位置元素
         * @param _2 第二位置元素
         */
        public Tuple2(final T _1, final U _2) {
            this._1 = _1;
            this._2 = _2;
        }

        /**
         * 返回第一元素
         *
         * @return 第一元素
         */
        public T _1() {
            return this._1;
        }

        /**
         * 返回 第二元素
         *
         * @return 第二元素
         */
        public U _2() {
            return this._2;
        }

        /**
         * 把 二元组 转换成一个 新的X的数据元素
         * @param mutator 变换器：(t,u)->X
         * @param <X> 变换结果的数据类型
         * @return X 类型的结果
         */
        public <X> X mutate(final BiFunction<T, U, X> mutator) {
            return mutator.apply(this._1, this._2);
        }

        /**
         * 数据格式化
         * @return 数据格式化
         */
        public String toString(){
            return "("+this._1+","+this._2+")";
        }

        /**
         * 构造一个二元组
         * @param _1 第一元素
         * @param _2 第二元素
         * @param <T> 第一元素类型
         * @param <U> 第二元素类型
         * @return 二元组对象的构造
         */
        public static <T,U>  Tuple2<T, U> TUP2(final T _1, final U _2){
            return new Tuple2<>(_1,_2);
        }

        protected T _1; // 第一位置元素
        protected U _2; // 第二位置元素

        /**
         * 把两个元素序列,tt,uu 合并成一个 [(t1,u1),(t2,u2),...] 的序列
         *
         * @param tt  第一元素序列
         * @param uu  第二元素序列
         * @param <T> 第一元素序列的元素类型
         * @param <U> 第二元素序列的元素类型
         * @return 二元组蓄力的元
         */
        public static <T, U> Stream<Tuple2<T, U>> zip(final T[] tt, final U[] uu) {
            return stm(Math.max(tt.length, uu.length)).map(i -> new Tuple2<>(tt[i % tt.length], uu[i % uu.length]));
        }
    }

    /**
     * 列表元素单元 (仿照LISP的 cons结构)
     *
     * @param <T> 列表元素的类型
     */
    public static class Elem<T> extends Tuple2<T, Elem<T>> {

        /**
         * 列表元素单元 (仿照LISP的 cons结构)
         *
         * @param _1 数组元素
         * @param _2 数组的父节点
         */
        public Elem(T _1, Elem<T> _2) {
            super(_1, _2);
        }

        /**
         * 对数据元素的列表进行数据规约
         * @param collector 数据元素的列的规约器
         * @param <X> 结果类型
         * @return X类型的结果
         */
        public <X> X collect(Collector<T,?,X>collector){
            return this.data().collect(collector);
        }

        /**
         * 把 列表元素单元 转换成一个 新的X的 结构对象
         * @param mutator 变换器:elem->X
         * @param <X> 变换结果的数据类型
         * @return X 类型的结果
         */
        public <X> X mutate(final Function<Elem<T>, X> mutator) {
            return mutator.apply(this);
        }

        /**
         * 列表元素单元 (仿照LISP的 cons结构) <br>
         * 数据元素的父亲节点为null,即构造了一个跟节点元素
         *
         * @param _1 数组元素
         */
        public Elem(T _1) {
            super(_1, null);
        }

        /**
         * 构造一个列表元素单元的结构,this 作为 t的父节点
         *
         * @param t 新的列表元素单元的数据
         * @return 构造一个列表元素单元的结构, this 作为 t的父节点
         */
        public Elem<T> cons(final T t) {
            return cons(t, this);
        }

        /**
         * 设置child的父节点为this
         *
         * @param child 子节点元素
         * @return child 子节点元素
         */
        public Elem<T> parentOf(final Elem<T> child) {
            if (child != null) child._2 = this;
            return child;
        }

        /**
         * 设置元素的父节点为parent
         *
         * @param parent 父节点元素
         * @return 元素本身
         */
        public Elem<T> childOf(final Elem<T> parent) {
            this._2 = parent;
            return this;
        }

        /**
         * 提取从根点到当前节点之上的节点路径上的所有数据元素
         *
         * @return 根点到当前节点之上的节点路径上的所有数据元素 构成的流
         */
        public Stream<T> data() {
            return data(this);
        }

        /**
         * 提取从根点到当前节点之上的节点路径上的所有数据元素
         * @param <U> 元素变换函数 的结果类型
         * @param mapper 元素变换函数 t->u
         * @return 根点到当前节点之上的节点路径上的所有数据元素 构成的流
         */
        public <U> Stream<U> dataS(final Function<T,U> mapper) {
            return this.data().map(mapper);
        }

        /**
         * 提取从根点到当前节点之上的节点路径上的所有数据元素
         *
         * @return 根点到当前节点之上的节点路径上的所有数据元素 构成的列表
         */
        public List<T> dataL() {
            return data(this).collect(Collectors.toList());
        }

        /**
         * 提取从根点到当前节点之上的节点路径上的所有数据元素
         *
         * @return 根点到当前节点之上的节点路径上的所有数据元素 构成的数组
         */
        @SuppressWarnings("unchecked")
        public T[] dataA() {
            return data(this).toArray(arr((Class<T>)this._1.getClass()));
        }

        /**
         * 构造一个列表元素单元的结构
         *
         * @param t    列表元素单元的数据
         * @param elem 列表元素单元的父节点
         * @param <T>  列表元素单元的数据类型
         * @return 列表元素单元的结构
         */
        public static <T> Elem<T> cons(final T t, final Elem<T> elem) {
            return new Elem<>(t, elem);
        }

        /**
         * 提取从根点到当前节点之上的节点路径上的所有数据元素
         *
         * @param elem 当前的列表元素元素单元
         * @param <T>  列表元素单元的 数据类型
         * @return 根点到当前节点之上的节点路径上的所有数据元素 构成的流
         */
        public static <T> Stream<T> data(final Elem<T> elem) {
            return elem._2 == null
                    ? S(elem._1)
                    : Stream.concat(data(elem._2), S(elem._1));
        }

        /**
         * 把一T类型的流转换成一个Elem的串列(Sequence)
         * @param stream T类型的数据流
         * @param <T> 数组元素
         * @return Elem的串列的末尾元素
         */
        public static <T> Elem<T> SEQ(final Stream<T> stream){
            return stream.map(Elem::new).reduce(null,(a,b)->b.childOf(a));
        }

        /**
         * 把一T类型的数组换成一个Elem的串列(Sequence)
         * @param tt T类型的数据数组
         * @param <T> 数组元素
         * @return Elem的串列的末尾元素
         */
        @SafeVarargs
        public static <T> Elem<T> SEQ(final T ... tt){
            return SEQ(Arrays.stream(tt));
        }

        /**
         * 把一T类型的数据集合换成一个Elem的串列(Sequence)
         * @param tt T类型的数据集合
         * @param <T> 数组元素
         * @return Elem的串列的末尾元素
         */
        public static <T> Elem<T> SEQ(final Collection<T> tt){
            return SEQ(tt.stream());
        }
    }

    /**
     * 对一个 元素集合序列 sss 做全排列
     *
     * @param sss 元素集合序列 ss0,ss1,....,ssn
     * @param <T> 元素集合序列 的数据类型
     * @return 元素集合序列 sss 做全排列
     */
    public static <T> Stream<Elem<T>> cph(final List<T[]> sss) {
        if(sss.size()<1){
            System.err.println("基础元素数组列表长度为0,至少需要包含有一个基础元素数组才能够做cph展开！");
            return Stream.of();
        }

        return sss.size() < 2
                ? S(sss.get(sss.size() - 1)).map(Elem::new)
                : cph(sss.subList(0, sss.size() - 1)).flatMap(p -> S(sss.get(sss.size() - 1)).map(p::cons));
    }

    /**
     * 对一个 元素集合序列 sss 做全排列
     *
     * @param sss 元素集合序列 ss0,ss1,....,ssn
     * @param <T> 元素集合序列 的数据类型
     * @return 元素集合序列 sss 做全排列
     */
    public static <T> Stream<List<T>> cph2(final List<T[]> sss) {
        return cph(sss).map(e -> e.data().collect(Collectors.toList()));
    }

    /**
     * 矩阵加法
     *
     * @param tt  第一矩阵
     * @param uu  第二矩阵
     * @param <T> 第一矩阵元素类型
     * @param <U> 第二矩阵元素类型
     * @return 结果矩阵
     */
    public static <T extends Number, U extends Number> Double[][] add(final T[][] tt, final U[][] uu) {
        final var shape_t = shape(tt);
        final var shape_u = shape(uu);
        final var shape = new Tuple2<>(Math.max(shape_t._1, shape_u._1), Math.max(shape_t._2, shape_u._2));
        return ij_yield(shape._1, shape._2,
                (i, j) -> tt[i % shape_t._1][j % shape_t._2].doubleValue() + uu[i % shape_u._1][j % shape_u._2].doubleValue(),
                Double.class);
    }

    /**
     * 矩阵加法
     *
     * @param tt  第一矩阵
     * @param u   第二矩阵 单元，采用 循环补填方式构造 与 tt 一直的同型矩阵
     * @param <T> 第一矩阵元素类型
     * @param <U> 第二矩阵元素类型
     * @return 结果矩阵
     */
    public static <T extends Number, U extends Number> Double[][] add(final T[][] tt, final U u) {
        final var uu = RPTA(1, A(u));
        return add(tt, uu);
    }

    /**
     * 矩阵减法
     *
     * @param tt  第一矩阵
     * @param uu  第二矩阵
     * @param <T> 第一矩阵元素类型
     * @param <U> 第二矩阵元素类型
     * @return 结果矩阵
     */
    public static <T extends Number, U extends Number> Double[][] sub(final T[][] tt, final U[][] uu) {
        final var shape_t = shape(tt);
        final var shape_u = shape(uu);
        final var shape = new Tuple2<>(Math.max(shape_t._1, shape_u._1), Math.max(shape_t._2, shape_u._2));
        return ij_yield(shape._1, shape._2,
                (i, j) -> tt[i % shape_t._1][j % shape_t._2].doubleValue() - uu[i % shape_u._1][j % shape_u._2].doubleValue(),
                Double.class);
    }

    /**
     * 矩阵减法
     *
     * @param tt  第一矩阵
     * @param u   第二矩阵 单元，采用 循环补填方式构造 与 tt 一直的同型矩阵
     * @param <T> 第一矩阵元素类型
     * @param <U> 第二矩阵元素类型
     * @return 结果矩阵
     */
    public static <T extends Number, U extends Number> Double[][] sub(final T[][] tt, final U u) {
        final var uu = RPTA(1, A(u));
        return sub(tt, uu);
    }

    /**
     * 矩阵乘法
     *
     * @param tt  第一矩阵
     * @param uu  第二矩阵
     * @param <T> 第一矩阵元素类型
     * @param <U> 第二矩阵元素类型
     * @return 结果矩阵
     */
    public static <T extends Number, U extends Number> Double[][] mul(final T[][] tt, final U[][] uu) {
        final var shape_t = shape(tt);
        final var shape_u = shape(uu);
        final var shape = new Tuple2<>(Math.max(shape_t._1, shape_u._1), Math.max(shape_t._2, shape_u._2));
        return ij_yield(shape._1, shape._2,
                (i, j) -> tt[i % shape_t._1][j % shape_t._2].doubleValue() * uu[i % shape_u._1][j % shape_u._2].doubleValue(),
                Double.class);
    }

    /**
     * 矩阵乘法
     *
     * @param tt  第一矩阵
     * @param u   第二矩阵 单元，采用 循环补填方式构造 与 tt 一直的同型矩阵
     * @param <T> 第一矩阵元素类型
     * @param <U> 第二矩阵元素类型
     * @return 结果矩阵
     */
    public static <T extends Number, U extends Number> Double[][] mul(final T[][] tt, final U u) {
        final var uu = RPTA(1, A(u));
        return mul(tt, uu);
    }

    /**
     * 矩阵乘法
     *
     * @param tt  第一矩阵
     * @param uu  第二矩阵
     * @param <T> 第一矩阵元素类型
     * @param <U> 第二矩阵元素类型
     * @return 结果矩阵
     */
    public static <T extends Number, U extends Number> Double[][] div(final T[][] tt, final U[][] uu) {
        final var shape_t = shape(tt);
        final var shape_u = shape(uu);
        final var shape = new Tuple2<>(Math.max(shape_t._1, shape_u._1), Math.max(shape_t._2, shape_u._2));
        return ij_yield(shape._1, shape._2, (i, j) ->
                        tt[i % shape_t._1][j % shape_t._2].doubleValue() /
                                uu[i % shape_u._1][j % shape_u._2].doubleValue(),
                Double.class);
    }

    /**
     * 矩阵除法
     *
     * @param tt  第一矩阵
     * @param u   第二矩阵 单元，采用 循环补填方式构造 与 tt 一直的同型矩阵
     * @param <T> 第一矩阵元素类型
     * @param <U> 第二矩阵元素类型
     * @return 结果矩阵
     */
    public static <T extends Number, U extends Number> Double[][] div(final T[][] tt, final U u) {
        final var uu = RPTA(1, A(u));
        return div(tt, uu);
    }

    /**
     * 矩阵除法
     *
     * @param tt  第一矩阵
     * @param uu  第二矩阵
     * @param <T> 第一矩阵元素类型
     * @param <U> 第二矩阵元素类型
     * @return 结果矩阵
     */
    public static <T extends Number, U extends Number> Double[][] div2(final T[][] tt, final U[][] uu) {
        final var shape_t = shape(tt);
        final var shape_u = shape(uu);
        final var shape = new Tuple2<>(Math.max(shape_t._1, shape_u._1), Math.max(shape_t._2, shape_u._2));
        return ij_yield(shape._1, shape._2, (i, j) ->
                        uu[i % shape_u._1][j % shape_u._2].doubleValue() /
                                tt[i % shape_t._1][j % shape_t._2].doubleValue(),
                Double.class);
    }

    /**
     * 矩阵除法
     *
     * @param tt  第一矩阵
     * @param u   第二矩阵 单元，采用 循环补填方式构造 与 tt 一直的同型矩阵
     * @param <T> 第一矩阵元素类型
     * @param <U> 第二矩阵元素类型
     * @return 结果矩阵
     */
    public static <T extends Number, U extends Number> Double[][] div2(final T[][] tt, final U u) {
        final var uu = RPTA(1, A(u));
        return div2(tt, uu);
    }

    /**
     * 求出一个矩阵的伴随矩阵
     *
     * @param tt  矩阵 m x n
     * @param <T> 矩阵的元素类型
     * @return 结果矩阵
     */
    public static <T extends Number> Double[][] adjugate(final T[][] tt) {
        final var shape = shape(tt);
        return ij_yield(shape._1, shape._2, (i, j) -> det(minor(tt, j, i)) * ((i + j) % 2 == 0 ? 1 : -1), Double.class);
    }

    /**
     * 求一个矩阵的逆
     *
     * @param tt  矩阵 m x n
     * @param <T> 矩阵的元素类型
     * @return 结果矩阵
     */
    public static <T extends Number> Double[][] inverse(final T[][] tt) {
        return div(adjugate(tt), det(tt));
    }
    
    /**
     * 施密特正交化(不做标准化)
     *
     * @param alphaA 向量数组(二维数组,每个第一维度的元素都代表一个向量)
     * @param <T>    矩阵元素类型
     * @return 正交化矩阵元素
     */
    public static <T extends Number> List<Double[]> schmidt(final T[][] alphaA) {
        return schmidt(alphaA,false);
    }
    
    /**
     * 施密特正交化
     *
     * @param alphaA 向量数组(二维数组,每个第一维度的元素都代表一个向量)
     * @param b      是对结果向量组进行标准化:false 不标化,true 标准化
     * @param <T>    矩阵元素类型
     * @return 正交化矩阵元素
     */
    public static <T extends Number> List<Double[]> schmidt(final T[][] alphaA,final boolean b) {
        return schmidt(Arrays.stream(alphaA),b);
    }

    /**
     * 施密特正交化(不做标准化)
     *
     * @param alphaL 向量矩阵列表
     * @param <T>    矩阵元素类型
     * @return 正交化矩阵元素
     */
    public static <T extends Number> List<Double[]> schmidt(final List<T[]> alphaL) {
        return schmidt(alphaL,false);
    }
    
    /**
     * 施密特正交化
     *
     * @param alphaL 向量矩阵列表
     * @param b      是对结果向量组进行标准化:false 不标化,true 标准化
     * @param <T>    矩阵元素类型
     * @return 正交化矩阵元素
     */
    public static <T extends Number> List<Double[]> schmidt(final List<T[]> alphaL,final boolean b) {
        return schmidt(alphaL.stream(),b);
    }

    /**
     * 施密特正交化(不做标准化)
     *
     * @param alphaS 向量矩阵列表
     * @param <T>    矩阵元素类型
     * @return 正交化矩阵元素
     */
    public static <T extends Number> List<Double[]> schmidt(final Stream<T[]> alphaS) {
        return schmidt(alphaS,false);
    }

    /**
     * 施密特正交化
     *
     * @param alphaS 向量矩阵列表
     * @param b      是对结果向量组进行标准化:false 不标化,true 标准化
     * @param <T>    矩阵元素类型
     * @return 正交化矩阵元素
     */
    public static <T extends Number> List<Double[]> schmidt(final Stream<T[]> alphaS,final boolean b) {
        final var betas = new ArrayList<Double[]>();
        final var eps = 1e-10;// 微小忽略量
        final Predicate<Number[]> is_not_zero = aa -> S(aa).allMatch(e -> Math.abs(e.doubleValue()) >= eps);// 与微小忽略量进行比较
        
        alphaS.filter(is_not_zero)
        .map(alpha -> betas.stream()
            .map(beta -> mul(-dot(alpha, beta) / dot(beta, beta), beta))
            .reduce(MatrixOps::add).map(e -> add(alpha, e))
            .orElse(S(alpha).map(Number::doubleValue).toArray(Double[]::new))
        ).filter(is_not_zero).map(e -> b ? div(e, Math.sqrt(dot(e, e))) : e).forEach(betas::add);
        
        return betas;
    }

    /**
     * 数组格式化
     *
     * @param tt  二维数组矩阵
     * @param <T> 数组元素
     * @return 格式化字符串
     */
    public static <T> String fmt(final T[][] tt) {
        final var nf = NumberFormat.getInstance();
        return S(tt).map(t -> S(t).map(e -> e instanceof Number ? nf.format(e): e + "")
           .collect(Collectors.joining("\t"))
        ).collect(Collectors.joining("\n"));
    }

    /**
     * 数组格式化
     *
     * @param tt  一维数组矩阵
     * @param <T> 数组元素
     * @return 格式化字符串
     */
    public static <T> String fmt(final T[] tt) {
        return Arrays.asList(tt).toString();
    }

    /**
     * 数组格式化
     *
     * @param tt  二维数组矩阵
     * @param <T> 数组元素
     * @return 格式化字符串
     */
    public static <T> String fmt2(final T[][] tt) {
        final var line = fmt(tt);
        System.out.println(line);
        return line;
    }

    /**
     * 数组格式化
     *
     * @param tt  一维数组矩阵
     * @param <T> 数组元素
     * @return 格式化字符串
     */
    public static <T> String fmt2(final T[] tt) {
        final var line = fmt(tt);
        System.out.println(line);
        return line;
    }

    /**
     * 复制一个数组 ，把元素  t 复制n词
     *
     * @param n   复制数量
     * @param t   复制元素
     * @param <T> 元素的类型
     * @return T类型的数组
     */
    @SuppressWarnings("unchecked")
    public static <T> T[] RPTA(final int n, final T t) {
        return stm(n).map(i -> t).toArray(arr((Class<T>) t.getClass()));
    }

    /**
     * 构造一个 复制一个数组 ，把元素  t 复制n次 的函数 <br>
     * Horizontalize repeaT 水平化复制
     * @param n   复制数量
     * @param <T> 元素的类型
     * @return T类型的数组 t->[t,t,t,...] 长度为n的数组的函数
     */
    @SuppressWarnings("unchecked")
    public static <T> Function<T, T[]> HT(final int n) {
        return t -> stm(n).map(i -> t).toArray(arr((Class<T>) t.getClass()));
    }

}